package com.jztd.platfrom.base.interceptor;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.google.common.collect.ImmutableMap;
import com.jztd.platfrom.base.exception.*;
import com.jztd.platfrom.base.model.Result;
import com.jztd.platfrom.base.util.HttpUtils;
import com.jztd.platfrom.base.util.ObjectUtils;
import db.sql.api.impl.cmd.condition.In;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.ErrorResponse;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 异常处理拦截器
 * @author lj
 * @date 2025/08/03
 */
@Controller
@RestControllerAdvice
public class GlobalExceptionInterceptor implements ErrorController {
    /**
     * 参数绑定结果格式化
     *
     * @param result 参数绑定结果
     *
     * @return 参数名称/异常消息映射表
     */
    private Map<String, String> format(BindingResult result) {
        List<FieldError> errors = ObjectUtils.ifNull(result, BindingResult::getFieldErrors);
        if (CollectionUtils.isEmpty(errors)) {
            return Collections.emptyMap();
        }
        return errors.stream()
                .collect(Collectors.toMap(FieldError::getField, e -> ObjectUtils.ifNull(e.getDefaultMessage(), ObjectUtils.EMPTY_STRING), (o, n) -> n));
    }

    /**
     * 参数类型异常格式化
     *
     * @param e 参数类型异常
     *
     * @return 参数名称/异常消息映射表
     */
    private Map<String, String> format(MethodArgumentTypeMismatchException e) {
        return ImmutableMap.of(e.getName(), ObjectUtils.ifNull(e.getRequiredType(), Class::getSimpleName, () -> ObjectUtils.EMPTY_STRING));
    }

    /**
     * 参数类型异常格式化
     *
     * @param e 参数校验异常
     *
     * @return 参数名称/异常消息映射表
     */
    private Map<String, String> format(HttpMessageNotReadableException e) {
        Throwable cause = e.getCause();
        if (cause instanceof InvalidFormatException) {
            List<JsonMappingException.Reference> references = ((InvalidFormatException) cause).getPath();
            if (!CollectionUtils.isEmpty(references)) {
                return references.stream().collect(Collectors.toMap(JsonMappingException.Reference::getFieldName, r -> "Invalid format"));
            }
        }
        return Collections.emptyMap();
    }



    /**
     * 异常方法
     *
     * @param response 请求响应对象
     * @param e        异常对象
     *
     * @return 异常结果
     */
    @RequestMapping("/error")
    public Result error(HttpServletResponse response, Exception e) {
        HttpStatus status = HttpUtils.getStatus(response.getStatus());
        HttpUtils.initializeUnifiedResponseHeader(response);
        return Result.builder()
                .code(status.value())
                .message(status.getReasonPhrase())
                .build();
    }

    /**
     * 异常转换
     *
     * @param response 请求响应对象
     * @param e        异常对象
     *
     * @return 请求结果
     */
    @ExceptionHandler(Exception.class)
    public Result exception(HttpServletResponse response, Exception e) {
        return exception( e);
    }

    /**
     * 将异常转换成结果对象
     *
     * @param e 异常对象
     *
     * @return 结果对象
     */
    private Result exception(Exception e) {
        if (e instanceof ServiceException) {
            Result result = this.serviceException((ServiceException) e);
           if(ObjectUtil.isNotEmpty(result)){
               return result;
           }
        }
        if (e instanceof HttpRequestMethodNotSupportedException) {
            return Result.build(HttpStatus.METHOD_NOT_ALLOWED);
        } else if (e instanceof HttpMediaTypeNotAcceptableException) {
            return Result.build(HttpStatus.NOT_ACCEPTABLE);
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            return Result.build(HttpStatus.UNSUPPORTED_MEDIA_TYPE);
        } else if (e instanceof HttpMessageNotReadableException) {
            Map<String, String> errors = this.format((HttpMessageNotReadableException) e);
            return CollectionUtils.isEmpty(errors) ? Result.build(HttpStatus.BAD_REQUEST)
                                                   : Result.build(HttpStatus.PRECONDITION_FAILED, errors);
        } else if (e instanceof HttpMessageConversionException || e instanceof ServletRequestBindingException) {
            return Result.build(HttpStatus.BAD_REQUEST);
        }  else if (e instanceof BindException) {
            return Result.build(HttpStatus.PRECONDITION_FAILED, this.format(((BindException) e).getBindingResult()));
        } else if (e instanceof MethodArgumentNotValidException) {
            return Result.build(HttpStatus.PRECONDITION_FAILED, this.format(((MethodArgumentNotValidException) e).getBindingResult()));
        } else if (e instanceof MethodArgumentTypeMismatchException) {
            return Result.build(HttpStatus.PRECONDITION_FAILED, this.format((MethodArgumentTypeMismatchException) e));
        }else if(e instanceof ServiceException){
            return serviceException((ServiceException)e);
        }
        return Result.build(500,"未知错误请联系管理员");
    }

    private Result serviceException(ServiceException e) {
        Boolean bool = ObjectUtil.isNotEmpty(e.getCode()) && e.getCode()>0;
        if (e instanceof UnauthenticatedException) {
            int status = bool ? e.getCode() : HttpStatus.UNAUTHORIZED.value();
            return Result.build(status, Optional.of(e.getMessage()).orElse("认证已失效，请重新认证"));
        } else if (e instanceof InvalidArgumentException) {
            int status = bool ? e.getCode() : HttpStatus.PRECONDITION_FAILED.value();
            return Result.build(status, Optional.of(e.getMessage()).orElse("参数不合法，请检查参数"));
        } else if (e instanceof ResourceAlreadyExistsException) {
            int status = bool ? e.getCode() : HttpStatus.CONFLICT.value();
            return Result.build(status, Optional.of(e.getMessage()).orElse("资源已存在"));
        } else if (e instanceof ResourceNotFoundException) {
            int status = bool ? e.getCode():HttpStatus.NOT_FOUND.value();
            return Result.build(status, Optional.of(e.getMessage()).orElse("资源未找到"));
        } else if (e instanceof TooManyRequestException) {
            int status = bool ? e.getCode():HttpStatus.TOO_MANY_REQUESTS.value();
            return Result.build(status, Optional.of(e.getMessage()).orElse("请求超出限制"));
        } else if (e instanceof PermissionDeniedException) {
            int status = bool ? e.getCode():HttpStatus.FORBIDDEN.value();
            return Result.build(status, Optional.of(e.getMessage()).orElse("暂无操作权限"));
        } else if(e instanceof BusinessException){
            int status = bool ? e.getCode() : 600;
            return Result.build(status, Optional.of(e.getMessage()).orElse("操作异常"));
        }
        return Result.build(501,"未知错误请联系管理员");
    }
}
